-- MineHillM
-- Created by panyl Jun/18/2015
-- 矿山（神龙夹层迷宫里出现）

module("MineHillM", package.seeall);

-- 矿山
local mineHill = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下mine_hill信息表
    local mine_hill_CSV = get_mine_hill_CSV();
    for i = 1, #mine_hill_CSV do
        mineHill[mine_hill_CSV[i].id] = mine_hill_CSV[i];
    end

    mine_hill_CSV = {};
end

function init()
    loadCsv();
end

-- 检索
function query(mineId, path)
    local m = mineHill[mineId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 尝试惊动守卫
function alarmGuard(mineId)
    for pos = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(pos);
        local monster = grid.monster;

        if grid:isOpened() and monster then
            local props = PropM.fetchProps(monster, "mine_keep");
            for _, prop in ipairs(props) do
                PropM.trigger(monster, prop[1], prop[2], mineId);
            end
        end
    end
end

-- 计算奖励
function calcBaseBonus(mineId, bonusType)
    local formula = query(mineId, bonusType);
    if type(formula) ~= "string" or #formula <= 0 then
        return;
    end

    -- 公式计算
    return FormulaM.invoke(formula, mineId);
end

-- 采矿掉落
function miningBonus(mineId)
    -- 掉落
    local bonus = calcBaseBonus(mineId, "drop_bonus");
    if bonus then
        -- 随机找一个位置
        local arr = findEmptyPos();
        local rand = DungeonM.getRandSeed("for_mine_pos");
        local emptyPos = arr[rand % #arr + 1];

        dropProperty(bonus, emptyPos);
    end

    -- 直接奖励
    bonus = calcBaseBonus(mineId, "direct_bonus");
    if bonus then
        BonusM.doBonus(bonus, "mine_bonus_" .. mineId);
    end
end

-- 矿脉枯竭
function mineBoneDry(minePos, mineId)
    local clear = true;

    for pos = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(pos);
        if grid.type == GRID_TYPE_MINE_HILL and
            grid.state ~= GRID_STATE_DISABLE then
            clear = false;
            break;
        end
    end

    -- 如果有需要记录字段
    local mineGrid = DungeonM.getGridByPos(minePos);
    local statKey = mineGrid.activity_bonus_stat;
    if statKey then
        BuildingBonusM.addFieldStat(statKey, 1);
    end

    -- 如果全部枯竭了
    local bonus = query(mineId, "clear_bonus");
    if clear and type(bonus) == "table" and #table.keys(bonus) > 0 then
        -- 掉落
        if bonus["drop"] then
            dropProperty(bonus["drop"], minePos);
        end

        -- 直接奖励
        if bonus["direct"] then
            BonusM.doBonus(bonus["direct"], "clear_mine_bonus");
        end
        return;
    end

    bonus = query(mineId, "bone_dry_bonus");
    if type(bonus) == "table" and #table.keys(bonus) > 0 then
        if bonus["drop"] then
            -- 掉落
            dropProperty(bonus["drop"], minePos);
        elseif bonus["direct"] then
            -- 直接奖励
            BonusM.doBonus(bonus["direct"], "bone_dry_bonus");
        elseif bonus["empty_drop"] then
            -- 空位掉落
            local emptyList = DungeonM.findEmptyGrids(false, true);
            local bonusList = FormulaM.invoke(bonus["empty_drop"], emptyList, minePos);
            for pos, bonus in pairs(bonusList) do
                dropProperty(bonus, pos, true);
            end
        end
    end
end

-- 掉落
function dropProperty(bonus, pos, effect)
    -- 掉落
    DungeonLogM.addLog("[MineHillM] drop property: " .. pos);
    local class = DungeonM.getClassByType(GRID_TYPE_ITEM);
    local dbase = {["bonus"] = bonus,};
    -- 钻石加一下漂浮和闪光
    if bonus[2] == "gem" then
        dbase = {["bonus"] = bonus, ["need_shadow"] = 1, ["need_shining"] = 1};
    elseif effect then
        dbase = {["bonus"] = bonus, ["need_shadow"] = 1, ["need_shining"] = 1};
    end
    DungeonM.transformGrid(class, pos, GRID_STATE_OPEN, dbase);
end

-- 找空位
function findEmptyPos()
    local ret = {};
    for pos = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(pos);
        if grid.type == GRID_TYPE_EMPTY or
            grid.state == GRID_STATE_DISABLE then
            table.insert(ret, pos);
        end
    end

    table.sort(ret);

    return ret;
end

-- 能否采矿
function canMining(pos)
    local grid = DungeonM.getGridByPos(pos);
    if grid.type ~= GRID_TYPE_MINE_HILL or
        grid.state == GRID_STATE_DISABLE then
        trace("MineHillM", "当前不能对%d进行采矿行为。", pos);
        return false;
    end

    -- 次数
    local leftTimes = grid.times or 0;
    if leftTimes <= 0 then
        trace("MineHillM", "矿山%d已经枯竭了。", pos);
        return false;
    end

    return true;
end

-- 采矿
function mining(pos)
    if not canMining(pos) then
        return false;
    end

    -- 没有位置
    local grid = DungeonM.getGridByPos(pos);
    local mineId = grid.mine_id;
    if type(query(mineId, "drop_bonus")) == "string" and #findEmptyPos() <= 0 then
        -- 没有空位可以掉落了
        return false;
    end

    -- 1. 先扣次数
    local leftTimes = grid.times - 1;
    grid.times = leftTimes;

    -- 掉落
    miningBonus(mineId);

    -- 如果已经枯萎了
    if leftTimes <= 0 then
        grid:changeState(GRID_STATE_DISABLE);

        -- 枯萎之后的处理
        mineBoneDry(pos, mineId);

        -- 抛出事件
        EventMgr.fire(event.MINE_HILL_BONE_DRY, {["pos"] = pos, });
    end

    -- 惊动守护者
    alarmGuard(mineId);

    -- 抛出一个事件
    local mineType = query(mineId, "type");
    EventMgr.fire(event.MINING, {["pos"] = pos, ["mineType"] = mineType, });

    if mineType == MINE_TYPE_NORMAL or mineType == MINE_TYPE_EGG then
        DungeonM.addAction({["cmd"] = "mining_normal", ["pos"] = pos, });
        EventMgr.fire(event.COMBAT_ROUND, pos);
    elseif mineType == MINE_TYPE_DIAMOND then
        DungeonM.addAction({["cmd"] = "mining_diamond", ["pos"] = pos, });
    end

    -- Action已经添加了
    return true, true;
end

-- 生成格子数据
function fetchMineData(ret, rand)
    if type(ret.times) == "table" then
        local nums = {};
        for i = ret.times[1], ret.times[2] do
            table.insert(nums, i);
        end
        table.sort(nums);
        local index = rand % #nums + 1;
        ret["times"] = nums[index];
    end

    return ret;
end